package com.ebupt.migu.common.util;

import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import com.alibaba.fastjson.JSONArray;

import lombok.extern.slf4j.Slf4j;

/**
 * Http 工具类优化版
 */
@Slf4j
public class HttpUtils {

    private static final int CONNECTION_TIMEOUT = 3000;
    private static final int SOCKET_TIMEOUT = 3000;
    private static final int CONNECTION_REQUEST_TIMEOUT = 3000;
    private static PoolingHttpClientConnectionManager connMgr;
    private static RequestConfig requestConfig;
    private static CloseableHttpClient httpClient;

    static {
        // 设置连接池
        connMgr = new PoolingHttpClientConnectionManager();
        connMgr.setMaxTotal(500);
        connMgr.setDefaultMaxPerRoute(10);

        RequestConfig.Builder configBuilder = RequestConfig.custom();
        // 设置连接超时
        configBuilder.setConnectTimeout(CONNECTION_TIMEOUT);
        // 设置读取超时
        configBuilder.setSocketTimeout(SOCKET_TIMEOUT);
        // 设置从连接池获取连接实例的超时
        configBuilder.setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT);
        requestConfig = configBuilder.build();
        httpClient = HttpClients.custom().setConnectionManager(connMgr).build();
    }

    /**
     * 发送 POST 请求（HTTP），K-V 形式
     *
     * @param apiUrl API 接口 URL
     * @param params 参数 map
     * @param headerParams header map
     * @return 请求响应结果字符串
     */
    public static String doPost(String apiUrl, Map<String, Object> params, Map<String, String> headerParams) {
        try {
            CloseableHttpClient client =
                HttpClients.custom().setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
            HttpPost httpPost = new HttpPost(apiUrl);
            String json = JsonUtils.obj2Json(params);
            StringEntity entitys = new StringEntity(json, "UTF-8");
            entitys.setContentType("application/json");
            httpPost.setEntity(entitys);
            if (headerParams.size() > 0) {
                Set<Entry<String, String>> set = headerParams.entrySet();
                for (Entry<String, String> entry : set) {
                    httpPost.addHeader(entry.getKey(), entry.getValue());
                }
            }
            CloseableHttpResponse response = client.execute(httpPost);
            HttpEntity entity = response.getEntity();
            String httpStr = EntityUtils.toString(entity, "UTF-8");
            EntityUtils.consume(response.getEntity());
            log.info("HTTP请求返回参数：{}", httpStr);
            return httpStr;
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 没有 header 的 post 请求
     *
     * @param apiUrl API 接口 URL
     * @param object 请求体对象
     * @return 请求响应结果字符串
     */
    public static String doPost(String apiUrl, Object object) {
        AtomicInteger retryCount = new AtomicInteger(0);
        while (retryCount.get() < 3) {
            try {
                CloseableHttpClient client =
                    HttpClients.custom().setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
                HttpPost httpPost = new HttpPost(apiUrl);
                String json = JSONArray.toJSON(object).toString();
                StringEntity entitys = new StringEntity(json, "UTF-8");
                entitys.setContentType("application/json");
                httpPost.setEntity(entitys);
                CloseableHttpResponse response = client.execute(httpPost);
                HttpEntity entity = response.getEntity();
                String httpStr = EntityUtils.toString(entity, "UTF-8");
                EntityUtils.consume(response.getEntity());
                return httpStr;
            } catch (IOException e) {
                log.error("请求发生异常，正在进行第 {} 次重试", retryCount.get() + 1, e);
                retryCount.incrementAndGet();
            }
        }
        throw new RuntimeException("请求重试三次后仍失败");
    }
}